package regions;

import java.util.LinkedList;

import base.Evaluation;
import base.PlayField;
import base.Tower;

//Algorithm class
public class RegionAlgorithm {
	
	public LinkedList<Region> regions;
	public Tower[][] towers;
	public int size;
	public int moves;
	
	//Constructor taking a playField only
	public RegionAlgorithm(PlayField playfield)
	{
		this.towers = playfield.towers;
		this.size = playfield.size;
		this.moves = playfield.moves;
		this.regions = new LinkedList<Region>();
	}
	
	//Main method for the Algorithm
	public void playGame()
	{
		
		//Main algorithm
		for(int i = 0 ; i <size; i++)
		{
			for(int j = 0; j < size; j++)
			{
				this.workTower(towers[i][j]);
			}
		}
		
		for(Region reg:this.regions)
		{
			System.out.println(reg.toString());
		}
		//TODO Create result
		
	}
	
	//Main work Tower method
	public void workTower(Tower tower)
	{
		//Get Neighbors, sorted
		LinkedList<Tower> neighbours = this.getNeighbours(tower);
		
		//Assess Situation and Make Adjustments to the Regions
		//Test the neighbors
		/*
		System.out.print(tower.rocks + " ->");
		
		for(int i=0; i< neighbours.size(); ++i)
		{
			System.out.print(neighbours.get(i).rocks);
		}
		
		System.out.println();
		*/
		
		//Try to cooperate with neighbors
		for(Tower neighb : neighbours)
		{
			if (neighb.region == null)
			{
				bandTogether(tower,neighb);
			}
			
			//If no region was added for the tower force
		}

	}
	
	/*
	//Evaluate and Adjust Regions
	private void evaluateAndAdjust(Tower tower, LinkedList<Tower> neighbours) {	
		
	}
	*/
	
	//Try add two towers into the same region if appropriate
	private boolean bandTogether(Tower tower, Tower neighb) {
		
		//If at the same region, return true
		if (tower.region != null && tower.region == neighb.region)
		{
			return true;
		}
		
		//If both alone, create a region
		if(tower.region == null && neighb.region == null)
		{
			createRegion(tower, neighb);
			
			return true;
		}
		
		//If already in a region, try To add to region
		if (tower.region!=null && neighb.region == null)
		{
			if (addToRegion(tower, neighb))
			{
				return true;
			}
		}

		if (tower.region==null && neighb.region != null)
		{
			if (addToRegion(neighb, tower))
			{
				return true;
			}
		}
		
		if (areCloseEnough(tower, neighb))
		{
			return tryForceGroupTogether(tower, neighb);
		}
		
		return false;
	}
	
	//Method for giving a relative evaluation of how close are two towers
	private boolean areCloseEnough(Tower tower, Tower neighb) {
		if (tower.rocks - neighb.rocks < neighb.rocks)
			return true;
		
		return true;
	}

	private boolean tryForceGroupTogether(Tower towerFirst, Tower neighb) {

		if (towerFirst.region.tryRemove(towerFirst) < neighb.rocks)
		{
			
		}
		
		return false;
	}
	
	//Creates  region
	public boolean createRegion(Tower a, Tower b)
	{
		Region newRegion = new Region(a, b);
		
		this.regions.add(newRegion);
		
		a.region = newRegion;
		
		b.region = newRegion;
		
		return true;
	}
	
	//Tries to add a tower to TowerFirst's Region
	public boolean addToRegion(Tower towerFirst, Tower tower)
	{
		Evaluation cost = towerFirst.region.costToAddTower(towerFirst,tower);
		
		//If there it can not be added but we want to
		if (cost == null)
		{
			//if (isGoodEnoughNeighbor(towerFirst, tower))
			//{
			//	trySplitRegion(towerFirst, tower);
				
			//	return true;
			//}
			//else
			//{
				return false;
			//}
		}
		
		if (isGoodEnough(towerFirst.region, cost))
		{
			towerFirst.region.addToRegion(towerFirst, tower, cost);
			
			return true;
		}
		
		return false;
	}
	
	private void trySplitRegion(Tower towerFirst, Tower tower) {
		// TODO Auto-generated method stub
		
	}

	private boolean isGoodEnoughNeighbor(Tower towerFirst, Tower tower) {
		// TODO Auto-generated method stub
		return false;
	}

	private boolean isGoodEnough(Region region, Evaluation costToAddTower) {

		if (costToAddTower.moves < costToAddTower.gain)
		{
			return true;
		}
		
		return false;
	}

	//Get the Neighbors of a Tower
	public LinkedList<Tower> getNeighbours(Tower input)
	{
		LinkedList<Tower> neighbours = new LinkedList<Tower>();
		
		//Check whether i boundary and add
		if (input.x>0)
		{
			neighbours.add(towers[input.x-1][input.y]);
		}
		
		if (input.x<this.size-1)
		{
			neighbours.add(towers[input.x+1][input.y]);
		}
		
		if (input.y>0)
		{
			neighbours.add(towers[input.x][input.y-1]);
		}
		
		if (input.y<this.size-1)
		{
			neighbours.add(towers[input.x][input.y+1]);
		}
		
		Tower temp;
		
		//Sort the list according to how close are the Towers to the center Tower
		for(int i=0; i< neighbours.size()-1;++i)
		{
			for(int j=i; j<neighbours.size()-1; ++j)
			{
				//If the difference with the center neighbout is bigger, swap
				if (Math.abs(input.rocks - neighbours.get(j).rocks)>Math.abs(input.rocks - neighbours.get(j+1).rocks))
				{
					//Swap the neighbours
					temp = neighbours.set(j, neighbours.get(j+1));
					neighbours.set(j+1, temp);
				}
			}
		}
				
		return neighbours;
	}
		
	public static void rearrangeRegions(Region regionA, Region regionB, Tower tower )
	{
		
	}
	
	public static void forceAddToRegion(Region region, Tower tower)
	{
		
	}
	public static LinkedList<String> getMovesEraseRegion(Region region)
	{
		return null;
	}
}
